package com.wenwan.manage.impl;

import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.github.wxpay.sdk.WXPayConstants.SignType;
import com.github.wxpay.sdk.WXPayUtil;
import com.google.gson.Gson;
import com.thoughtworks.xstream.XStream;
import com.wenwan.manage.mapper.RedisDao;
import com.wenwan.manage.pojo.BuyReleaseTimes;
import com.wenwan.manage.pojo.OrderInfo;
import com.wenwan.manage.pojo.OrderReturnInfo;
import com.wenwan.manage.pojo.ReleaseTimes;
import com.wenwan.manage.pojo.SignInfo;
import com.wenwan.manage.pojo.WeiXinOpenId;
import com.wenwan.manage.service.ReleaseTimesService;
import com.wenwan.manage.service.ReleaseTimesWaterAccountService;
import com.wenwan.manage.service.UserService;
import com.wenwan.manage.service.WeiXinRequestPaymentService;
import com.wenwan.manage.setting.RegExpSetting;
import com.wenwan.manage.setting.StatusSetting;
import com.wenwan.manage.setting.WeiXinSetting;
import com.wenwan.manage.util.Configure;
import com.wenwan.manage.util.HttpRequest;
import com.wenwan.manage.util.RandomStringGenerator;
import com.wenwan.manage.util.Signature;
import com.wenwan.manage.util.Util;

@Service
public class WeiXinRequestPaymentServiceImpl implements WeiXinRequestPaymentService {

	/**
	 * 购买发布次数统一下单
	 */
	@Override
	public Map<String, Object> BuyReleaseTimesRequestPayment(String code, String releaseTimesId, Integer number,
			String userId) {
		// TODO Auto-generated method stub
		// DataToObject<Object> dto = new DataToObject<Object>();
		Map<String, Object> dto = new HashMap<String, Object>();

		if (code != null && !code.matches(RegExpSetting.WEI_XIN_LOGIN_CODE)) {
			dto.put("data", false);
			dto.put("msg", "code" + StatusSetting.MSG_10050_FORMAT_IS_MISTAKE);
			dto.put("code", StatusSetting.CODE_10050);
			// dto.setData(false);
			// dto.setMsg(StatusSetting.MSG_10050_FORMAT_IS_MISTAKE);
			// dto.setCode(StatusSetting.CODE_10050);
			return dto;
		}

		if (releaseTimesId != null && !releaseTimesId.matches(RegExpSetting.PARA_ID)) {
			dto.put("data", false);
			dto.put("msg", "releaseTimesId" + StatusSetting.MSG_10050_FORMAT_IS_MISTAKE);
			dto.put("code", StatusSetting.CODE_10050);
			// dto.setData(false);
			// dto.setMsg(StatusSetting.MSG_10050_FORMAT_IS_MISTAKE);
			// dto.setCode(StatusSetting.CODE_10050);
			return dto;
		}

		if (number != null && number < 1) {
			dto.put("data", false);
			dto.put("msg", "number" + StatusSetting.MSG_10050_IS_CAN_NOT_LESS_ONE);
			dto.put("code", StatusSetting.CODE_10050);
			// dto.setData(false);
			// dto.setMsg(StatusSetting.MSG_10050_IS_CAN_NOT_LESS_ONE);
			// dto.setCode(StatusSetting.CODE_10050);
			return dto;
		}

		if (userId != null && !userId.matches(RegExpSetting.PARA_ID)) {
			dto.put("data", false);
			dto.put("msg", "userId" + StatusSetting.MSG_10050_FORMAT_IS_MISTAKE);
			dto.put("code", StatusSetting.CODE_10050);
			// dto.setData(false);
			// dto.setMsg("userId" + StatusSetting.MSG_10050_FORMAT_IS_MISTAKE);
			// dto.setCode(StatusSetting.CODE_10050);
			return dto;
		}

		Map<String, String> map = new HashMap<String, String>();
		try {

			WeiXinOpenId weiXinOpenId = getOpenid(code);
			String prepay_id = xiaDan(weiXinOpenId.getOpenid(), releaseTimesId, number, userId);
			map = sign(prepay_id);
			// dto.setData(map);
			dto.put("data", map);
			dto.put("msg", StatusSetting.MSG_200);
			dto.put("code", StatusSetting.CODE_200);
			return dto;

		} catch (UnrecoverableKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (KeyManagementException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (KeyStoreException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return dto;
	}

	private static Map<String, String> sign(String repay_id) throws IllegalAccessException {

		Map<String, String> map = new HashMap<String, String>();

		SignInfo signInfo = new SignInfo();

		signInfo.setAppId(Configure.getAppID());
		long time = System.currentTimeMillis() / 1000;
		signInfo.setTimeStamp(String.valueOf(time));
		signInfo.setNonceStr(RandomStringGenerator.getRandomStringByLength(32));
		signInfo.setRepay_id("prepay_id=" + repay_id);
		signInfo.setSignType("MD5");
		// 生成签名
		String sign = Signature.getSign(signInfo);

		map.put("timeStamp", signInfo.getTimeStamp());
		map.put("nonceStr", signInfo.getNonceStr());
		map.put("package", signInfo.getRepay_id());
		map.put("signType", signInfo.getSignType());
		map.put("paySign", sign);

		return map;

	}

	private WeiXinOpenId getOpenid(String code) throws ClientProtocolException, IOException {
		// TODO Auto-generated method stub
		HttpGet httpGet = new HttpGet("https://api.weixin.qq.com/sns/jscode2session?appid=" + WeiXinSetting.APPID
				+ "&secret=" + WeiXinSetting.SECRET + "&js_code=" + code + "&grant_type=authorization_code");
		// 设置请求器的配置
		HttpClient httpClient = HttpClients.createDefault();
		HttpResponse res = httpClient.execute(httpGet);
		HttpEntity entity = res.getEntity();
		String result = EntityUtils.toString(entity, "UTF-8");
		WeiXinOpenId weiXinOpenId = new Gson().fromJson(result, WeiXinOpenId.class);
		System.out.println(result);
		return weiXinOpenId;
	}

	// 统一下单
	private String xiaDan(String openid, String releaseTimesId, Integer number, String userId)
			throws IllegalAccessException, UnrecoverableKeyException, KeyManagementException, ClientProtocolException,
			KeyStoreException, NoSuchAlgorithmException, IOException {
		// TODO Auto-generated method stub
		OrderInfo order = new OrderInfo();
		order.setAppid(WeiXinSetting.APPID);
		order.setMch_id(WeiXinSetting.MCH_ID);

		// 随机字符串
		// String nonce_str = RandomStringGenerator.getRandomStringByLength(32);
		String nonce_str = Util.UUID();
		order.setNonce_str(nonce_str);

		// 商户订单号
		// String out_trade_no = RandomStringGenerator.getRandomStringByLength(32);
		String out_trade_no = Util.UUID();
		order.setOut_trade_no(out_trade_no);

		// 商品简介
		String body = WeiXinSetting.BUY_RELEASE_TIMES_BODY;
		order.setBody(body);

		// 缓存订单
		putBuyReleseTimes(nonce_str, out_trade_no, body, releaseTimesId, number, userId);

		// 获取商品的金额
		Integer total_fee = getTotalReeByReleaseTimesIdAndNumber(releaseTimesId, number);
		if (total_fee == null) {
			return null;// 商品不存在
		}
		order.setTotal_fee(total_fee);

		order.setSpbill_create_ip("127.0.0.1");
		order.setNotify_url(WeiXinSetting.BUY_RELEASE_TIMES_NOTIFY_URL);
		order.setTrade_type(WeiXinSetting.BUY_TRADE_TYPE);
		order.setOpenid(openid);
		order.setSign_type(WeiXinSetting.BUY_SIGN_TYPE);
		// 生成签名
		String sign = Signature.getSign(order);
		order.setSign(sign);
		String result = HttpRequest.sendPost(WeiXinSetting.PAY_UNIFIEDORDER, order);
		System.out.println(result);
		XStream xStream = new XStream();
		xStream.alias("xml", OrderReturnInfo.class);

		OrderReturnInfo returnInfo = (OrderReturnInfo) xStream.fromXML(result);

		return returnInfo.getPrepay_id();
	}

	@Autowired
	private ReleaseTimesService releaseTimesService;

	private Integer getTotalReeByReleaseTimesIdAndNumber(String releaseTimesId, Integer number) {
		// TODO Auto-generated method stub
		Integer total_fee = 0;
		ReleaseTimes releaseTimes = (ReleaseTimes) releaseTimesService.selectOneById(releaseTimesId).get("data");
		if (releaseTimes != null) {// 如果商品不等于空,获得金额
			total_fee = (int) ((releaseTimes.getPrice() * releaseTimes.getDiscount()) * 100);
		} else {
			return null;
		}
		return total_fee;
	}

	// 缓存订单
	private void putBuyReleseTimes(String nonce_str, String out_trade_no, String body, String releaseTimesId,
			Integer number, String userId) {
		// TODO Auto-generated method stub
		RedisDao redisDao = new RedisDao();
		BuyReleaseTimes buyReleaseTimes = new BuyReleaseTimes();
		System.out.println("----nonce_str----" + nonce_str);
		buyReleaseTimes.setId(nonce_str);
		// 订单ID
		buyReleaseTimes.setReleaseTimesId(releaseTimesId);
		// 获取商品当前的信息
		ReleaseTimes releseTimes = (ReleaseTimes) releaseTimesService.selectOneById(releaseTimesId).get("data");
		// 添加当前购买商品进缓存
		buyReleaseTimes.setReleaseTimes(releseTimes);
		// 购买数量
		buyReleaseTimes.setNumber(number);
		// 是否已处理
		buyReleaseTimes.setIsHandle(false);
		// 商户订单号
		buyReleaseTimes.setOutTradeNo(out_trade_no);
		// 商品简介
		buyReleaseTimes.setBody(body);
		// 购买的账号
		buyReleaseTimes.setUserId(userId);
		// 缓存
		redisDao.putBuyReleaseTimes(buyReleaseTimes);
	}

	@Autowired
	private UserService userService;

	@Autowired
	private ReleaseTimesWaterAccountService releaseTimesWaterAccountService;

	/**
	 * 购买发布次数结果回调
	 */
	private String buyReleaseTimesPayResult(Map<String, Object> map) {

		// TODO Auto-generated method stub

		String result = "";// 返回给微信的处理结果
		Boolean endsign = (Boolean) map.get("endsign");
		System.out.println(endsign);
		// 验证签名
		if (endsign) {
			System.err.println("SUCCESS,OK");
			// 签名成功。
			// 执行失付成功之后的操作。
			System.out.println("签名成功");
			// 获取用户唯一标识
			String openid = (String) map.get("openid");
			System.out.println("openid:" + openid);
			// 缓存订单的id
			String nonceStr = (String) map.get("nonce_str");
			System.out.println("nonceStr:" + nonceStr);
			// 微信订单号
			String transactionId = (String) map.get("transaction_id");
			System.out.println("transactionId:" + transactionId);
			// 获取缓存
			RedisDao redisDao = new RedisDao();
			// 获取购买的商品
			BuyReleaseTimes buyReleaseTimes = redisDao.getBuyReleaseTimes(nonceStr);
			System.out.println("buyReleaseTimes:" + buyReleaseTimes);
			if (buyReleaseTimes != null) {

				System.out.println("订单是否已处理:" + buyReleaseTimes.getIsHandle());
				if (!buyReleaseTimes.getIsHandle()) {// 如果此订单未处理
					// 获取所购买的商品缓存
					ReleaseTimes releseTimes = buyReleaseTimes.getReleaseTimes();
					// 获取购买发布次数所得到的次数(所购买量*单个商品所获得的次数)
					Integer times = (releseTimes.getTimes() + releseTimes.getGiveTimes()) * buyReleaseTimes.getNumber();
					System.out.println("获得的次数：" + times);
					// 获取用户信息
					// User user = userService.selectOneByOpenid(openid).getData();
					// System.out.println("用户ID：" + user.getId());
					// 为用户添加次数
					if (buyReleaseTimes.getUserId() != null && times != null) {// 如果用户不为空

						// 添加进流水账
						Boolean data = (Boolean) releaseTimesWaterAccountService.create(buyReleaseTimes.getUserId(),
								buyReleaseTimes.getBody(), true, buyReleaseTimes.getOutTradeNo(), transactionId,
								releseTimes.getPrice(), releseTimes.getDiscount(), releseTimes.getTimes(),
								releseTimes.getGiveTimes(), buyReleaseTimes.getNumber()).get("data");

						System.out.println("流水账是否添加成功：" + data);

						if (data != null && data) {// 如果添加流水账成功

							data = (Boolean) userService
									.update(buyReleaseTimes.getUserId(), null, null, null, null, null, times, null)
									.get("data");
							System.out.println("用户购买次数是否成功：" + data);

							if (data) {
								// 如果用户添加发布次数成功
								// 更新缓存
								buyReleaseTimes.setIsHandle(true);
								redisDao.putBuyReleaseTimes(buyReleaseTimes);
								// 回调给微信
								result = setXml("SUCCESS", "OK");
								return result;

							} else {
								// 用户添加发布次数失败，不处理，继续接收微信回调
							}

						}

					}

				} else {// 此订单已处理

					result = setXml("SUCCESS", "OK");
					System.out.println("回调成功");
					System.out.println("----返回给微信的xml：" + result);
					return result;

				}

			}

		} else {// 签名不一致

			System.err.println("签名不一致！");
			result = setXml("fail", "签名不一致！");
			return result;
		}

		System.out.println("回调成功");
		System.out.println("----返回给微信的xml：" + result);
		return result;

	}

	// 通过xml 发给微信消息
	public static String setXml(String return_code, String return_msg) {
		SortedMap<String, String> parameters = new TreeMap<String, String>();
		parameters.put("return_code", return_code);
		parameters.put("return_msg", return_msg);
		return "<xml><return_code><![CDATA[" + return_code + "]]>" + "</return_code><return_msg><![CDATA[" + return_msg
				+ "]]></return_msg></xml>";
	}

	@Override
	public String buyReleaseTimesPayResult(String notityXml) {
		// TODO Auto-generated method stub

		Boolean endsign = false;
		SortedMap<String, Object> parameters = new TreeMap<String, Object>();

		// 微信给返回的东西
		try {

			// while ((inputLine = request.getReader().readLine()) != null) {
			// notityXml += inputLine;
			// }

			System.out.println(notityXml);

			// request.getReader().close();

			Map<String, String> map = WXPayUtil.xmlToMap(notityXml);

			System.out.println(map);

			// 解析各种数据
			String appid = (String) map.get("appid");// 应用ID
			String attach = (String) map.get("attach");// 商家数据包
			String bank_type = (String) map.get("bank_type");// 付款银行
			String cash_fee = (String) map.get("cash_fee");// 现金支付金额
			String fee_type = (String) map.get("fee_type");// 货币种类
			String is_subscribe = (String) map.get("is_subscribe");// 是否关注公众账号
			String mch_id = (String) map.get("mch_id");// 商户号
			String nonce_str = (String) map.get("nonce_str");// 随机字符串
			String openid = (String) map.get("openid");// 用户标识
			String out_trade_no = (String) map.get("out_trade_no");// 获取商户订单号
			String result_code = (String) map.get("result_code");// 业务结果
			String return_code = (String) map.get("return_code");// SUCCESS/FAIL
			String sign = (String) map.get("sign");// 获取签名
			String time_end = (String) map.get("time_end");// 支付完成时间
			String total_fee = (String) map.get("total_fee");// 获取订单金额
			String trade_type = (String) map.get("trade_type");// 交易类型
			String transaction_id = (String) map.get("transaction_id");// 微信支付订单号

			// 数据加密
			parameters.put("appid", appid);// 应用ID
			parameters.put("attach", attach);// 商家数据包
			parameters.put("bank_type", bank_type);// 付款银行
			parameters.put("cash_fee", cash_fee);// 现金支付金额
			parameters.put("fee_type", fee_type);// 货币种类
			parameters.put("is_subscribe", is_subscribe);// 是否关注公众账号
			parameters.put("mch_id", mch_id);// 商户号
			parameters.put("nonce_str", nonce_str);// 随机字符串
			parameters.put("openid", openid);// 用户标识
			parameters.put("out_trade_no", out_trade_no);// 商户订单号
			parameters.put("result_code", result_code);// 业务结果
			parameters.put("return_code", return_code);// SUCCESS/FAIL
			parameters.put("time_end", time_end);// 支付完成时间
			parameters.put("total_fee", total_fee);// 获取订单金额
			parameters.put("trade_type", trade_type);// 交易类型
			parameters.put("transaction_id", transaction_id);// 微信支付订单号

			// 加密前验证notify支付订单网关---https://gw.tenpay.com/gateway/simpleverifynotifyid.xml
			// RequestHandler reqHandler = new RequestHandler(request, response);
			// reqHandler.init(appid, appsecret, partnerkey);
			// MD5加密

			endsign = WXPayUtil.isSignatureValid(map, Configure.getKey(), SignType.MD5);

			System.out.println(
					"**************************************************************************************************");
			System.out.println(appid + "-------------------应用ID");
			System.out.println(attach + "-------------------商家数据包");
			System.out.println(bank_type + "-------------------付款银行");
			System.out.println(cash_fee + "-------------------现金支付金额");
			System.out.println(fee_type + "-------------------货币种类");
			System.out.println(is_subscribe + "-------------------是否关注公众账号");
			System.out.println(mch_id + "-------------------商户号");
			System.out.println(nonce_str + "-------------------随机字符串");
			System.out.println(openid + "-------------------用户标识");
			System.out.println(out_trade_no + "-------------------获取商户订单号");
			System.out.println(result_code + "-------------------业务结果");
			System.out.println(return_code + "------------------- SUCCESS/FAIL");
			System.out.println(sign + "-------------------获取签名-微信回调的签名");
			System.out.println(time_end + "-------------------支付完成时间");
			System.out.println(total_fee + "-------------------获取订单金额");
			System.out.println(trade_type + "-------------------交易类型");
			System.out.println(transaction_id + "-------------------微信支付订单号");
			System.out.println(endsign + "-------------------第二次加密sign");
			System.out.println(
					"**************************************************************************************************");

		} catch (Exception e) {
			e.printStackTrace();
		}

		parameters.put("endsign", endsign);

		return buyReleaseTimesPayResult(parameters);
	}

}
